package main

import (
	"encoding/json"
	"encoding/base64"
	"fmt"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
)

type Config struct {
	EdgeTTSPath string `json:"edge_tts_path"`
	Port        string `json:"port"`
	BasePath    string `json:"base_path"`
}

var appConfig Config

func main() {
	// Load configuration
	configData, err := ioutil.ReadFile("config.json")
	if err != nil {
		log.Fatalf("Error reading config.json: %v", err)
	}
	if err := json.Unmarshal(configData, &appConfig); err != nil {
		log.Fatalf("Error unmarshaling config.json: %v", err)
	}

	http.HandleFunc(appConfig.BasePath+"/", serveHTML)
	http.HandleFunc(appConfig.BasePath+"/synthesize", synthesizeSpeech)

	if appConfig.Port == "" {
		appConfig.Port = "8080" // Default port
	}
	log.Printf("Server started on http://localhost:%s%s", appConfig.Port, appConfig.BasePath)
	log.Fatal(http.ListenAndServe(":"+appConfig.Port, nil))
}

func serveHTML(w http.ResponseWriter, r *http.Request) {
	tmpl, err := template.ParseFiles("html/index.html")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	tmpl.Execute(w, nil)
}

func synthesizeSpeech(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "Only POST requests are allowed", http.StatusMethodNotAllowed)
		return
	}

	text := r.FormValue("text")
	if text == "" {
		http.Error(w, "Text cannot be empty", http.StatusBadRequest)
		return
	}

	// Log received parameters
	log.Printf("Received parameters: Text='%s', Voice='%s', Rate='%s', Pitch='%s', Volume='%s'",
		text, r.FormValue("voice"), r.FormValue("rate"), r.FormValue("pitch"), r.FormValue("volume"))

	// Create temporary files for audio and subtitles
	audioFileName := fmt.Sprintf("output_%d.mp3", os.Getpid())
	audioFilePath := filepath.Join("temp", audioFileName)
	subtitleFileName := fmt.Sprintf("output_%d.vtt", os.Getpid())
	subtitleFilePath := filepath.Join("temp", subtitleFileName)

	// Ensure the temp directory exists
	if _, err := os.Stat("temp"); os.IsNotExist(err) {
		os.Mkdir("temp", 0755)
	}

	// Call edge-tts
	voice := r.FormValue("voice")
	rate := r.FormValue("rate")
	pitch := r.FormValue("pitch")
	volume := r.FormValue("volume")
	generateSubtitles := r.FormValue("generateSubtitles") == "true"

	args := []string{"--text", text, "--write-media", audioFilePath}
	if voice != "" {
		args = append(args, "--voice", voice)
	}
	if rate != "" {
		args = append(args, "--rate", rate)
	}
	if pitch != "" {
		args = append(args, "--pitch", pitch)
	}
	// edge-tts volume parameter expects a relative value like +0% or -10%
	// If the volume is 100 (default from frontend), it means +0% change.
	// Otherwise, we assume the frontend sends a value that can be directly used or converted.
	if volume != "" && volume != "100" {
		// Assuming frontend sends a value that can be directly used by edge-tts if not 100
		// For example, if frontend sends "+10%" or "-5%"
		args = append(args, "--volume", volume)
	} else if volume == "100" {
		// If volume is 100, it means no change from default, which is +0% for edge-tts
		args = append(args, "--volume", "+0%")
	}

	if generateSubtitles {
		args = append(args, "--write-subtitles", subtitleFilePath)
	}

	cmd := exec.Command(appConfig.EdgeTTSPath, args...)
	cmd.Stderr = os.Stderr // Redirect stderr to see edge-tts errors

	// Log the full command being executed
	log.Printf("Executing command: %s %v", appConfig.EdgeTTSPath, args)

	err := cmd.Run()
	if err != nil {
		log.Printf("Error running edge-tts: %v", err)
		http.Error(w, "Failed to synthesize speech", http.StatusInternalServerError)
		return
	}

	// Read the generated audio file
	audioBytes, err := ioutil.ReadFile(audioFilePath)
	if err != nil {
		log.Printf("Error reading audio file: %v", err)
		http.Error(w, "Failed to read audio file", http.StatusInternalServerError)
		return
	}

	// Prepare response data
	response := struct {
		AudioBase64 string `json:"audioBase64"`
		Subtitles   string `json:"subtitles"`
	}{
		AudioBase64: base64.StdEncoding.EncodeToString(audioBytes),
	}

	// Read subtitles if generated
	if generateSubtitles {
		subtitleBytes, err := ioutil.ReadFile(subtitleFilePath)
		if err != nil {
			log.Printf("Error reading subtitle file: %v", err)
			// Don't return error, just proceed without subtitles
		} else {
			response.Subtitles = string(subtitleBytes)
		}
	}

	// Set appropriate headers and send JSON response
	w.Header().Set("Content-Type", "application/json")
	if err := json.NewEncoder(w).Encode(response); err != nil {
		log.Printf("Error encoding JSON response: %v", err)
		http.Error(w, "Failed to encode response", http.StatusInternalServerError)
		return
	}

	// Clean up temporary files
	defer os.Remove(audioFilePath)
	if generateSubtitles {
		defer os.Remove(subtitleFilePath)
	}
}
